using System;
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using MPS.Blazor.Menus;
using MPS.EntityFrameworkCore;
using MPS.Localization;
using MPS.MultiTenancy;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Bundling;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;
using Volo.Abp.UI.Navigation;
using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.VirtualFileSystem;
using DK.Abp.AspnetCore.Components.Server.BootstrapBlazorTheme;
using DK.Abp.IdentityManagement.Blazor.Server.BootstrapBlazorUI;
using DK.Abp.SettingManagement.Blazor.Server.BootstrapBlazorUI;
using DK.Abp.TenantManagement.Blazor.Server.BootstrapBlazorUI;
using DK.Abp.AspnetCore.Components.Web.BootstrapBlazorTheme.Routing;
using DK.Abp.AspnetCore.Components.Server.BootstrapBlazorTheme.Bundling;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Danikor.Abp.AspNetCore.Mvc.UI;
using Danikor.SerialNumberManagement.Web;
using Danikor.MessageManagement.Web;
using Danikor.FormManagement.Web;
using Danikor.FormManagement;
using Volo.Abp.BlobStoring;
using Volo.Abp.BlobStoring.FileSystem;

namespace MPS.Blazor;

[DependsOn(
    typeof(MPSApplicationModule),
    typeof(MPSEntityFrameworkCoreModule),
    typeof(MPSHttpApiModule),
    typeof(AbpAutofacModule),
    typeof(AbpSwashbuckleModule),
    typeof(AbpAspNetCoreSerilogModule),
    typeof(AbpAspNetCoreComponentsServerBootstrapBlazorThemeModule),
    typeof(AbpAspNetCoreMvcUiLeptonXLiteThemeModule),
    typeof(AbpIdentityBlazorServerBootstrapBlazorModule),
    typeof(AbpTenantManagementBlazorServerBootstrapBlazorModule),
    typeof(AbpSettingManagementBlazorServerBootstrapBlazorModule),
    typeof(DanikorAbpAspNetCoreMvcUiModule),
    typeof(FormManagementWebModule),
    typeof(SerialNumberManagementWebModule),
    typeof(MessageManagementWebModule)

   )]
public class MPSBlazorModule : AbpModule
{
    public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        var hostingEnvironment = context.Services.GetHostingEnvironment();
        var configuration = context.Services.GetConfiguration();

        context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
        {
            options.AddAssemblyResource(
                typeof(MPSResource),
                typeof(MPSDomainModule).Assembly,
                typeof(MPSDomainSharedModule).Assembly,
                typeof(MPSApplicationModule).Assembly,
                typeof(MPSApplicationContractsModule).Assembly,
                typeof(MPSBlazorModule).Assembly
            );
        });

        //PreConfigure<OpenIddictBuilder>(builder =>
        //{
        //    builder.AddValidation(options =>
        //    {
        //        options.AddAudiences("MPS");
        //        options.UseLocalServer();
        //        options.UseAspNetCore();
        //    });
        //});

        //if (!hostingEnvironment.IsDevelopment())
        //{
        //    PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
        //    {
        //        options.AddDevelopmentEncryptionAndSigningCertificate = false;
        //    });

        //    PreConfigure<OpenIddictServerBuilder>(serverBuilder =>
        //    {
        //        serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "72aebdf5-5427-4bb7-ab6c-53533ca6d697");
        //    });
        //}
    }

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var hostingEnvironment = context.Services.GetHostingEnvironment();
        var configuration = context.Services.GetConfiguration();

        FormManagementDbProperties.DbTablePrefix = MPSConsts.DanikorModuleTablePrefix;

        ConfigureAuthentication(context, configuration);
        ConfigureUrls(configuration);
        ConfigureBundles();
        ConfigureAutoMapper();
        ConfigureVirtualFileSystem(hostingEnvironment);
        ConfigureSwaggerServices(context.Services);
        ConfigureAutoApiControllers();
        //ConfigureBlazorise(context);
        ConfigureRouter(context);
        ConfigureMenu(context);
        Configure<AbpBlobStoringOptions>(options =>
        {
            options.Containers.Configure<FormFileContainer>(container => {
                container.UseFileSystem(fileSystem => {
                    fileSystem.BasePath = configuration["Settings:FileSystemPath"];
                });
            });
        });
    }

    private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
           .AddCookie("Cookies", options =>
           {
               options.ExpireTimeSpan = TimeSpan.FromDays(365);
           })
           .AddOpenIdConnect("oidc", options =>
           {
               options.Authority = configuration["AuthServer:Authority"];
               options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
               options.ResponseType = OpenIdConnectResponseType.CodeIdToken;

               options.ClientId = configuration["AuthServer:ClientId"];
               options.ClientSecret = configuration["AuthServer:ClientSecret"];

               options.UsePkce = true;
               options.SaveTokens = true;
               options.GetClaimsFromUserInfoEndpoint = true;

               options.Scope.Add("roles");
               options.Scope.Add("email");
               options.Scope.Add("phone");
               options.Scope.Add("MPS");
           });
    }

    private void ConfigureUrls(IConfiguration configuration)
    {
        Configure<AppUrlOptions>(options =>
        {
            options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
            options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"]?.Split(',') ?? Array.Empty<string>());
        });
    }

    private void ConfigureBundles()
    {
        Configure<AbpBundlingOptions>(options =>
        {
            // MVC UI
            options.StyleBundles.Configure(
                LeptonXLiteThemeBundles.Styles.Global,
                bundle =>
                {
                    bundle.AddFiles("/global-styles.css");
                }
            );

            //BLAZOR UI
            options.StyleBundles.Configure(
                BlazorBootstrapBlazorThemeBundles.Styles.Global,
                bundle =>
                {
                    bundle.AddFiles("/blazor-global-styles.css");
                    //You can remove the following line if you don't use Blazor CSS isolation for components
                    bundle.AddFiles("/MPS.Blazor.styles.css");
                }
            );
        });
    }

    private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment)
    {
        if (hostingEnvironment.IsDevelopment())
        {
            Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.ReplaceEmbeddedByPhysical<MPSDomainSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}MPS.Domain.Shared"));
                options.FileSets.ReplaceEmbeddedByPhysical<MPSDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}MPS.Domain"));
                options.FileSets.ReplaceEmbeddedByPhysical<MPSApplicationContractsModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}MPS.Application.Contracts"));
                options.FileSets.ReplaceEmbeddedByPhysical<MPSApplicationModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}MPS.Application"));
                options.FileSets.ReplaceEmbeddedByPhysical<MPSBlazorModule>(hostingEnvironment.ContentRootPath);
            });
        }
    }

    private void ConfigureSwaggerServices(IServiceCollection services)
    {
        services.AddAbpSwaggerGen(
            options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo { Title = "MPS API", Version = "v1" });
                options.DocInclusionPredicate((docName, description) => true);
                options.CustomSchemaIds(type => type.FullName);
            }
        );
    }

    //private void ConfigureBlazorise(ServiceConfigurationContext context)
    //{
    //    context.Services
    //        .AddBootstrap5Providers()
    //        .AddFontAwesomeIcons();
    //}

    private void ConfigureMenu(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();
        Configure<AbpNavigationOptions>(options =>
        {
            options.MenuContributors.Add(new MPSMenuContributor(configuration));
        });
    }

    private void ConfigureRouter(ServiceConfigurationContext context)
    {
        Configure<AbpRouterOptions>(options =>
        {
            options.AppAssembly = typeof(MPSBlazorModule).Assembly;
        });
    }

    private void ConfigureAutoApiControllers()
    {
        Configure<AbpAspNetCoreMvcOptions>(options =>
        {
            options.ConventionalControllers.Create(typeof(MPSApplicationModule).Assembly);
        });
    }

    private void ConfigureAutoMapper()
    {
        Configure<AbpAutoMapperOptions>(options =>
        {
            options.AddMaps<MPSBlazorModule>();
        });
    }

    public override void OnApplicationInitialization(ApplicationInitializationContext context)
    {
        var env = context.GetEnvironment();
        var app = context.GetApplicationBuilder();

        app.UseAbpRequestLocalization();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseCorrelationId();
        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthentication();

        if (MultiTenancyConsts.IsEnabled)
        {
            app.UseMultiTenancy();
        }
        app.UseUnitOfWork();
        app.UseDynamicClaims();
        app.UseAuthorization();

        app.UseSwagger();
        app.UseAbpSwaggerUI(options =>
        {
            options.SwaggerEndpoint("/swagger/v1/swagger.json", "MPS API");
        });

        app.UseConfiguredEndpoints();
    }
}
